bs4 模块的介绍


1. bs4 模块的介绍

  • bs4 全名 BeautifulSoup,是编写 python 爬虫常用库之一,主要用来解析 html 标签(即: 直接定位获取指定的标签内容)

2. bs4 模块的解析原理

  1. 将即将要进行解析的源码加载到bs对象
  2. 调用bs对象中相关的方法或属性进行源码中的相关标签的定位
  3. 将定位到的标签之间存在的文本或者属性值进行获取

bs4 模块的安装


pip3 install bs4 -i https://pypi.douban.com/simple # 使用豆瓣的镜像

bs4 模块的初始化


1. 初始化

  • 实例化 BeautifulSoup 对象需要传入两个参数

    • 参数一: html字符串 或 文件句柄
    • 参数二: 解析器

  • 解析器的说明

    • 如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的

解析器
使用方法
优势
Python标准库(自带)
BeautifulSoup(html, "html.parser")
  1. Python的内置标准库
  2. 执行速度适中
  3. 文档容错能力强
lxml HTML(第三方)
BeautifulSoup(html, "lxml")
  1. 速度快
  2. 文档容错能力强
lxml XML(第三方)
BeautifulSoup(html, ["lxml", "xml"])
BeautifulSoup(html, "xml")
  1. 速度快
  2. 唯一支持XML的解析器
html5lib(第三方)
BeautifulSoup(html, "html5lib")
  1. 最好的容错性
  2. 以浏览器的方式解析文档
  3. 生成HTML5格式的文档
  • 解析器的安装

    • lxml

pip3 install lxml -i https://pypi.douban.com/simple # 使用豆瓣的镜像

    • html5lib

pip3 install html5lib -i https://pypi.douban.com/simple # 使用豆瓣的镜像

  • bs4 模块使用的固定写法

from bs4 import BeautifulSoup

soup = BeautifulSoup('html字符串 或 文件句柄', '解析器')

  • 获取指定html字符串中的标签内容

from bs4 import BeautifulSoup

soup = BeautifulSoup('<a>123</a> <a>321</a>', 'lxml')
print(soup.a)

  • 获取指定html文件中的标签内容

# xxx.html

<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>测试bs4</title>
</head>
<body>
<div>
    <p>百里守约</p>
</div>
<div class="song">
    <p>李清照</p>
    <p>王安石</p>
    <p>苏轼</p>
    <p>柳宗元</p>
    <a href="http://www.song.com/" title="赵匡胤" target="_self">
        <span>this is span</span>
        宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
    <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
    <img src="http://www.baidu.com/meinv.jpg" alt=""/>
</div>
<div class="tang">
    <ul>
        <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
        <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
        <li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
        <li><a href="http://www.sina.com" class="du">杜甫</a></li>
        <li><a href="http://www.dudu.com" class="du">杜牧</a></li>
        <li><b>杜小月</b></li>
        <li><i>度蜜月</i></li>
        <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
    </ul>
</div>
</body>
</html>

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')
print(soup.a)

bs4 模块的使用(HTML标签节点的相关操作


注意: 这里所使用的 html 文件就是上面的 xxx.html 文件内容

1. 根据标签名查找

  • bs对象.标签名 -> 获取第一个符合要求的标签

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

a = soup.a

print(a)  # <a href="http://www.song.com/" target="_self" title="赵匡胤"><span>this is span</span>宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>

2. find -> 找到第一个符合要求的标签

  • find(name=None, attrs={}, recursive=True, text=None, **kwargs) 方法的参数说明

    • name: 查找标签名为 name 的标签
    • attrs: 按属性名和值查找 -> 传入字典,key 为属性名,value 为属性值
    • recursive: 是否递归遍历所有子孙节点,默认 True
    • text: 用于搜索字符串,会找到 .string 方法与 text 参数值相符的tag,通常配合正则表达式使用。也就是说,虽然参数名是 text,但实际上搜索的是 string 属性
    • **kwargs: 如果一个参数名不是find方法内置的参数名,搜索时会把该参数当作标签的属性来搜索。这里注意,如果要按 class 属性搜索,因为 class 是 python 的保留字,需要写作 class_

  • bs对象.find('标签名')

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p = soup.find('p')

print(p)  # <p>百里守约</p>

  • bs对象.find(attrs={标签属性名: '标签属性值', ……})

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

attrs = {
    'href': 'http://www.dudu.com',
    'class': 'du'
}

tag = soup.find(attrs=attrs)

print(tag)  # <a class="du" href="http://www.dudu.com">杜牧</a>

  • bs对象.find('标签名', attrs={标签属性名: '标签属性值', ……})

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

attrs = {
    'href': 'http://www.dudu.com',
    'class': 'du'
}

tag = soup.find('a', attrs=attrs)

print(tag) # <a class="du" href="http://www.dudu.com">杜牧</a>

  • bs对象.find('标签名', 标签属性名='标签属性值')

    • 注意: 如果是 class 属性名要在其后面加上 _ 使用(即: class_)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

a1 = soup.find('a', id="xxx")

a2 = soup.find('a', class_="xxx")

a3 = soup.find('a', title="xxx")

a4 = soup.find('a', alt="xxx")

  • bs对象.find(标签属性名='标签属性值')

    • 注意: 如果是 class 属性名要在其后面加上 _ 使用(即: class_)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

du = soup.find(class_='du')

print(du)  # <a class="du" href="">总为浮云能蔽日,长安不见使人愁</a>

3. find_all -> 找到所有符合要求的标签

  • find_all(self, name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs)方法的参数说明

    • name: 查找标签名为 name 的标签
    • attrs: 按属性名和值查找 -> 传入字典,key 为属性名,value 为属性值
    • recursive: 是否递归遍历所有子孙节点,默认 True
    • text: 用于搜索字符串,会找到 .string 方法与 text 参数值相符的tag,通常配合正则表达式使用。也就是说,虽然参数名是 text,但实际上搜索的是 string 属性
    • limit: 找到所有指定的标签, 且只获取前 num 个
    • **kwargs: 如果一个参数名不是find方法内置的参数名,搜索时会把该参数当作标签的属性来搜索。这里注意,如果要按 class 属性搜索,因为 class 是 python 的保留字,需要写作 class_

  • bs对象.find_all() -> 找到所有标签(即: 不传任何参数,直接获取所有标签)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

tag_list = soup.find_all()

print(len(tag_list))  # 34

for tag in tag_list:
    print(tag)

  • bs对象.find_all('标签名') -> 找到所有指定的标签

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_list = soup.find_all('p') # 获取所有p标签

print(p_list)  # [<p>百里守约</p>, <p>李清照</p>, <p>王安石</p>, <p>苏轼</p>, <p>柳宗元</p>]

  • bs对象.find_all(['标签名', '标签名']) -> 找到所有指定的标签

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_list = soup.find_all(['p', 'span']) # 获取所有 p 标签 和 span 标签

print(p_list)  # [<p>百里守约</p>, <p>李清照</p>, <p>王安石</p>, <p>苏轼</p>, <p>柳宗元</p>, <span>this is span</span>]

  • bs对象.find_all(attrs={标签属性名: '标签属性值', ……})

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

attrs = {
    'class': 'du'
}

tag = soup.find_all(attrs=attrs)

print(tag)  # [<a class="du" href="">总为浮云能蔽日,长安不见使人愁</a>, ……]

  • bs对象.find_all('标签名', attrs={标签属性名: '标签属性值', ……})

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

attrs = {
    'class': 'du'
}

tag = soup.find_all('a', attrs=attrs)

print(tag)  # [<a class="du" href="">总为浮云能蔽日,长安不见使人愁</a>, ……]

  • bs对象.find_all(标签属性名='标签属性值') -> 根据标签属性名和属性值找到指定的标签

    • 注意: 如果是 class 属性名要在其后面加上 _ 使用(即: class_)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

du_list = soup.find_all(class_='du')

print(du_list)  # [<a class="du" href="">……</a>, ……]

  • bs对象.find_all('标签名', 标签属性名='标签属性值') -> 根据标签名和标签属性名和属性值找到指定的标签

    • 注意: 如果是 class 属性名要在其后面加上 _ 使用(即: class_)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

du_list = soup.find_all('a', class_='du')

print(du_list)  # [<a class="du" href="">……</a>, ……]

  • bs对象.find_all('标签名', limit=num) -> 找到所有指定的标签, 且只获取前 num 个

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_list = soup.find_all('p', limit=2) # 获取所有p标签中的前2个

print(p_list)  # [<p>百里守约</p>, <p>李清照</p>]

4.根据选择器选择指定的标签 -> 即: 可以根据css中的选择器选择指定的标签

  • bs对象.select('选择器') -> 根据选择器获取所有标签

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

li_list = soup.select('.tang > ul > li')

print(li_list)  # [<li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>, ……]

  • bs对象.select_one('选择器') -> 根据选择器获取第一个标签

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p = soup.select_one('.song p')

print(p)  # <p>李清照</p>

5.根据正则选择指定的标签

  • bs对象.find/find_all/select(re.compile('正则表达式'))

import re
from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

is_i_tag = soup.find_all(re.compile("i") # 获取标签中有i这个字符的标签

print(is_i_tag)

6.其他获取节点的属性

  • 父节点

    • 标签对象.parent -> 获取指定元素的父节点

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_parent = soup.find('p').parent

print(p_parent)  # <div>……<div>

    • 标签对象.parents -> 获取指定元素的所有父节点(即: 返回一个可迭代对象)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_parents = soup.find('p').parents

print(p_parents)  # <generator object parents at 0x000001A27EA30888>

for parent in p_parents:
    print(parent)

  • 子节点

    • 标签对象.contents -> 获取指定元素下的所有子节点(即: 返回一个所有子节点的列表)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

li_list = soup.find('ul').contents

print(li_list)  # [<li>……</li>, ……]

    • 标签对象.children -> 获取指定元素下的所有子节点(即: 返回一个所有子节点的可迭代对象)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

list_iterator = soup.find('ul').children

print(list_iterator)  # <list_iterator object at 0x0000025B4B1B0C50>

for li in list_iterator:
    print(li)

    • 标签对象.descendants -> 获取指定元素下的所有子孙节点(即: 返回一个所有子孙节点的可迭代对象)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

generator = soup.find('ul').descendants

print(generator)  # <generator object descendants at 0x000002B4BB920888>

for li in generator:
    print(li)

  • 兄弟节点

    • 标签对象.next_sibling -> 获取指定元素的下一个兄弟元素

      • 注意标签之间必须是相邻的不能有回车,否则无法获取

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

next_tag = soup.select_one('.song p').next_sibling

print(next_tag)  # <p>王安石</p>

    • 标签对象.previous_sibling -> 获取指定元素的上一个兄弟元素

      • 注意标签之间必须是相邻的不能有回车,否则无法获取

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

previous_tag = soup.select_one('.song img').previous_sibling

print(previous_tag)  # <a class="du" href="">总为浮云能蔽日,长安不见使人愁</a>

    • 标签对象.next_siblings -> 获取指定元素下面的所有兄弟元素(即: 返回一个可迭代对象)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

next_tags = soup.select_one('.song p').next_siblings

print(next_tags)  # <generator object next_siblings at 0x000002C7B2C90888>

for next_tag in next_tags:
    print(next_tag)

    • 标签对象.previous_siblings -> 获取指定元素上面的所有兄弟元素(即: 返回一个可迭代对象)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

previous_tags = soup.select_one('.song img').previous_siblings

print(previous_tags)  # <generator object previous_siblings at 0x000001D3E65B0888>

for previous_tag in previous_tags:
    print(previous_tag)

7.其他获取节点的方法

  • find_parents() -> 返回所有祖先节点
  • find_parent() -> 返回直接父节点
  • find_next_siblings() -> 返回后面所有的兄弟节点
  • find_next_sibling() -> 返回后面的第一个兄弟节点
  • find_previous_siblings() -> 返回前面所有的兄弟节点
  • find_previous_sibling() -> 返回前面第一个兄弟节点
  • find_all_next() -> 返回节点后所有符合条件的节点
  • find_next() -> 返回节点后第一个符合条件的节点
  • find_all_previous() -> 返回节点前所有符合条件的节点
  • find_previous() -> 返回节点前所有符合条件的节点

8.删除节点

  • 标签对象.decompose() -> 删除节点

  • 删除第一个p标签

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

soup.find('p').decompose()  # 删除p标签

print(soup)

  • 删除所有a标签

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

a_list = soup.find_all('a')

for a in a_list:
    a.decompose()  # 删除a标签

print(soup)

标签对象的说明


  • 标签对象就是通过 bs对象 获取指定标签后得到的 标签对象

  • 在打印标签对象的时候虽然显示出来的是一个或一组标签,但是实际上它是一个对象

  • 当使用 bs对象.标签名 或 bs对象.find('标签名') 等都可以直接得到一个标签对象

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

a = soup.a  # 返回一个标签对象
print(type(a))  # <class 'bs4.element.Tag'>
print(a)  # <a>……</a>
print(a.string)

p = soup.find('p')  # 返回一个标签对象
print(type(p))  # <class 'bs4.element.Tag'>
print(p)  # <p>百里守约</p>
print(p.string)

  • 当使用 bs对象.find_all('标签名') 或 bs对象.select('选择器') 等获取多个标签的时候,此时每一个标签对象已经存放在列表中,想要获取每个标签对象就需要进行遍历操作

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_list = soup.find_all('p')

for p in p_list:
    print(type(p))
    print(p)
    print(p.string)

"""
<class 'bs4.element.Tag'>
<p>百里守约</p>
百里守约
<class 'bs4.element.Tag'>
<p>李清照</p>
李清照
<class 'bs4.element.Tag'>
<p>王安石</p>
王安石
<class 'bs4.element.Tag'>
<p>苏轼</p>
苏轼
<class 'bs4.element.Tag'>
<p>柳宗元</p>
柳宗元
"""

bs4 模块的使用(标签属性的相关操作


1.获取标签中的属性

  • 标签对象.attrs -> 获取该标签下的所有的属性和属性值,返回一个字典

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

a_attrs = soup.a.attrs

print(a_attrs)  # {'href': 'http://www.song.com/', 'title': '赵匡胤', 'target': '_self'}

2.获取标签中的指定属性

  • 标签对象.attrs['属性名'] -> 非简写

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

a_attrs = soup.a.attrs['href']

print(a_attrs)  # http://www.song.com/

  • 标签对象['属性名'] -> 简写

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

a_attrs = soup.a['href']

print(a_attrs)  # http://www.song.com/

  • 标签对象.get('属性名') -> 简写

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

a_attrs = soup.a.get('href')

print(a_attrs)  # http://www.song.com/

3.修改标签中的属性

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

soup.find('a').attrs['href'] = 'https://www.baidu.com'

print(soup)

4. 删除标签中的属性

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

del soup.find('a').attrs['href']

print(soup)

bs4 模块的使用(HTML节点内容的相关操作)


1.获取标签中的内容

  • 标签对象.string -> 获取指定标签中的内容

    • 返回值: 字符串

    • 如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_content = soup.p.string

print(p_content)  # 百里守约

  • 标签对象.text

    • 返回值: 字符串

    • 获取指定标签的内容

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_content = soup.p.text

print(p_content)  # 百里守约

    • 获取指定标签子级的所有内容(即: 获取ul下的li中的所有内容)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

li_content = soup.ul.text

print(li_content)

"""
li_content所获取到的内容

清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村
秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山
岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君
杜甫
杜牧
杜小月
度蜜月
凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘
"""

  • 标签对象.get_text() -> 和 .text 功能类似

    • 返回值: 字符串

    • 获取指定标签的内容

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_content = soup.p.get_text()

print(p_content)  # 百里守约

    • 获取指定标签子级的所有内容(即: 获取ul下的li中的所有内容)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

li_content = soup.ul.get_text()

print(li_content)

"""
li_content所获取到的内容

清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村
秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山
岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君
杜甫
杜牧
杜小月
度蜜月
凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘
"""

  • 标签对象.stripped_strings()

    • 返回值: 可迭代对象

    • 获取指定标签的内容

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

p_list = soup.p.stripped_strings

print(p_list)  # <generator object stripped_strings at 0x000001B6252A0888>

print(list(p_list))  # ['百里守约']

    • 获取指定标签子级的所有内容(即: 获取ul下的li中的所有内容)

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

li_content = soup.ul.stripped_strings

print(li_content)  # <generator object stripped_strings at 0x0000021728E30888>

print(list(li_content))  # ['清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村', ……]

bs4 模块的使用(其他相关操作)


1. 获取标签名

  • 标签对象.name

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')
tag_name = soup.find('p').name
print(tag_name)  # p

from bs4 import BeautifulSoup

soup = BeautifulSoup(open('xxx.html', encoding='utf-8'), 'lxml')

for tag in soup.find_all():
    tag_name = tag.name
    print(tag_name)

爬虫项目


  • 使用bs4实现将诗词名句网站中三国演义小说的每一章的内容爬去到本地磁盘进行存储

import requests
from bs4 import BeautifulSoup

url = 'http://www.shicimingju.com/book/sanguoyanyi.html'  # 三国演义目录地址

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'}

page_text = requests.get(url=url, headers=headers).text  # 获取三国演义的目录内容

soup = BeautifulSoup(page_text, 'lxml')  # 实例化 三国演义的目录内容 的bs对象

a_list = soup.select('.book-mulu li a')  # 获取所有目录章节的a标签

with open('sanguo.txt', 'w', encoding='utf-8') as f:
    for a in a_list:
        title = a.string  # 获取章节标题
        detail_url = 'http://www.shicimingju.com%s' % a['href']  # 获取章节详情页地址并且进行拼接
        detail_page_text = requests.get(url=detail_url, headers=headers).text  # 获取文章详情页的内容
        detail_soup = BeautifulSoup(detail_page_text, 'lxml')  # 实例化 详情页 的bs对象
        content = detail_soup.select_one('.chapter_content').text  # 获取 .chapter_content 下的所有子节点的内容
        f.write(title + '\n' + content)  # 写入 txt 文件中

print('over!!')